home *** CD-ROM | disk | FTP | other *** search
/ FM Towns: Free Software Collection 11 / FM Towns Free Software Collection 11.iso / t_os / tool / artemis1 / src / plt16.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-11  |  8.6 KB  |  389 lines

  1. /*
  2.     ARTemis (Graphic Editor for FM-TOWNS)
  3.     (c) MATSUUCHI Ryosuke 1992
  4.  
  5.     plt16.c
  6.  
  7.     16色モードにおいてパレットどうしの混色や近似パレット検索を行うときの処理
  8. */
  9.  
  10.  
  11. #include <stdio.h>
  12. #include <malloc.h>
  13. #include <egb.h>
  14. #include <memory.h>
  15.  
  16. #include <math2.h>
  17. #include <decimal.h>
  18.  
  19. #include "ge.h"
  20. #include "plt16.h"
  21.  
  22.  
  23. #if NO16==0
  24.  
  25.  
  26. //     (local) 指定したパレット番号のパレットを得る
  27. //-----------------------------------------------------------------------
  28.  
  29.  
  30. static grb_t _getplt(int plt)
  31. {
  32.     unsigned char pal_[4+8*16];
  33.     EGB_getPalette(1,(char *)pal_);
  34.     return    (int)((pal_[4+8*plt+4+2]>>4)&15)*256 +
  35.             (int)((pal_[4+8*plt+4+1]>>4)&15)* 16 +
  36.             (int)((pal_[4+8*plt+4  ]>>4)&15);
  37. }
  38.  
  39.  
  40. //     (local) 指定したパレット番号のパレットを設定する
  41. //-----------------------------------------------------------------------
  42.  
  43.  
  44. static void _setplt(int plt, grb_t grb)
  45. {
  46.     char pal_[4+8*16];
  47.     DWORD(pal_ + 0) = 1;
  48.     DWORD(pal_ + 4) = plt;
  49.     BYTE (pal_ + 8) = (grb&15) << 4;
  50.     BYTE (pal_ + 9) = ((grb>>4)&15)<<4;
  51.     BYTE (pal_ +10) = ((grb>>8)&15)<<4;
  52.     BYTE (pal_ +11) = 0;
  53.     EGB_palette(_egbwork,0,pal_);
  54. }
  55.  
  56.  
  57. //     (local) grb_t カラーどうしの「相違度(difference)」を計算する
  58. //-----------------------------------------------------------------------
  59.  
  60.  
  61. /*
  62.     static int _coldiff(grb_t grb1, grb_t grb2)
  63.     {
  64.         static int exp2[] =
  65.             { 0,1,4,9,16,25,36,49,64,81,
  66.               100,121,144,169,196,225,256 };
  67.         return      exp2[_abs((int)((grb1>>8)&15)-(int)((grb2>>8)&15))]
  68.                 + exp2[_abs((int)((grb1>>4)&15)-(int)((grb2>>4)&15))]
  69.                 + exp2[_abs((int)(grb1&15)-(int)(grb2&15))];
  70.     }
  71. */
  72.  
  73.  
  74. static void RGB_YCrCb(int *grb, deci *ycc)
  75. {
  76.     static const int A[4][4] = {
  77.         {FDeci( 0.29900), FDeci( 0.58700), FDeci( 0.11400)},
  78.         {FDeci( 0.50000), FDeci(-0.41869), FDeci(-0.08131)},
  79.         {FDeci(-0.16874), FDeci(-0.33126), FDeci( 0.50000)}
  80.     };
  81.     ycc[0] = A[0][0] * grb[1] + A[0][1] * grb[0] + A[0][2] * grb[2];
  82.     ycc[1] = A[1][0] * grb[1] + A[1][1] * grb[0] + A[1][2] * grb[2];
  83.     ycc[2] = A[2][0] * grb[1] + A[2][1] * grb[0] + A[2][2] * grb[2];
  84.     return;
  85. }
  86.  
  87.  
  88. static int _coldiff(grb_t grb1, grb_t grb2)
  89. {
  90.     int grb[2][4];
  91.     deci ycc[2][4];
  92.     grb[0][0]=(grb1>>8)&15; grb[0][1]=(grb1>>4)&15; grb[0][2]=(grb1)&15;
  93.     grb[1][0]=(grb2>>8)&15; grb[1][1]=(grb2>>4)&15; grb[1][2]=(grb2)&15;
  94.     RGB_YCrCb(grb[0], ycc[0]);
  95.     RGB_YCrCb(grb[1], ycc[1]);
  96.     int t,d;
  97.     d = 0;
  98.     // 色相(Cr,Cb)の相違
  99.     t = ycc[0][1] - ycc[1][1];        t = MulDeci(MulDeci(t,t),FDeci(0.7));
  100.     d += DeciToInt(t);
  101.     t = ycc[0][2] - ycc[1][2];        t = MulDeci(MulDeci(t,t),FDeci(0.8));
  102.     d += DeciToInt(t);
  103.     // 輝度(Y)の相違
  104.     t = ycc[0][0] - ycc[1][0];        t = MulDeci(t,t);
  105.     d += DeciToInt(t);
  106.     return d;
  107. }
  108.  
  109.  
  110. //     (local) 近似パレットリストのための型定義・変数定義
  111. //-----------------------------------------------------------------------
  112.  
  113.  
  114. typedef struct _nearplt_e {        // 近似パレットリストの1要素(NEARPLTの補助)
  115.     struct _nearplt_e *next;
  116.     bool            used;
  117.     char            plt;
  118.     short int        dist;
  119. } NEARPLTe;
  120.  
  121.  
  122. typedef    struct {                // ある grb_t カラーに対する近似パレットリスト
  123.     NEARPLTe    *neartop;
  124.     NEARPLTe    near[16];
  125. } NEARPLT;
  126.  
  127.  
  128. static    NEARPLT    *nearplt;    // 全 grb_t カラーに対する近似パレットリスト
  129. static    grb_t    pltgrb[16];    // 各パレットの現在の設定状態
  130.  
  131.  
  132. //     (local) 近似パレットリストへの要素の挿入
  133. //-----------------------------------------------------------------------
  134.  
  135.  
  136. static void NEARPLT_ins(grb_t grb, int plt)
  137. // [grb_tカラー grb に対する近似パレットリストに、plt 番のパレットを挿入する]
  138. //        この関数は、grb_tカラー grb に対する近似パレットリストに plt 番の
  139. //        パレットがまだ登録されていない状態で呼ばなくてはいけない。
  140. {
  141.     NEARPLT *nplt;
  142.     int dist;
  143.     nplt = nearplt + grb;
  144.     dist = _coldiff(grb, pltgrb[plt]);
  145.     if (nplt->neartop == NULL)
  146.     {
  147.         NEARPLTe *p;
  148.         p = &(nplt->near[0]);
  149.         p->next = NULL;
  150.         p->used = YES;
  151.         p->plt = plt;
  152.         p->dist = dist;
  153.         nplt->neartop = p;
  154.     }
  155.     else
  156.     {
  157.         int i;
  158.         register NEARPLTe *p1,*p2;
  159.         bool done;
  160.         NEARPLTe *p;
  161.         done = NO;
  162.         for (p1=nplt->neartop,p2=NULL;  p1!=NULL;  p2=p1,p1=p1->next)
  163.         {
  164.             if (dist < p1->dist)
  165.             {
  166.                 done = YES;
  167.                 for (i=0; i<16; i++)
  168.                     if (! nplt->near[i].used)    break;
  169.                 if (i==16)
  170.                     return;
  171.                 p = &(nplt->near[i]);
  172.                 p->used = YES;
  173.                 p->next = p1;
  174.                 p->plt = plt;
  175.                 p->dist = dist;
  176.                 if (p2 == NULL)
  177.                     nplt->neartop = p;
  178.                 else
  179.                     p2->next = p;
  180.                 break;
  181.             }
  182.         }
  183.         if (!done)
  184.         {
  185.             for (i=0; i<16; i++)
  186.                 if (! nplt->near[i].used)    break;
  187.             if (i==16)
  188.                 return;
  189.             p = &(nplt->near[i]);
  190.             p->used = YES;
  191.             p->next = NULL;
  192.             p->plt = plt;
  193.             p->dist = dist;
  194.             if (p2 == NULL)
  195.                 nplt->neartop = p;
  196.             else
  197.                 p2->next = p;
  198.         }
  199.     }
  200. }
  201.  
  202.  
  203. //     (local) 近似パレットリストの要素の削除
  204. //-----------------------------------------------------------------------
  205.  
  206.  
  207. static void NEARPLT_del(int grb, int plt)
  208. // [grb_tカラー grb に対する近似パレットリストの中から、
  209. //   plt番のパレットの要素を削除する]
  210. //          この関数は、リスト中に見つかった plt 番のパレット要素をすべて
  211. //            削除する。また、リスト中に plt 番のパレット要素が存在しなくても
  212. //            問題はない。
  213. {
  214.     NEARPLT *nplt;
  215.     nplt = nearplt + grb;
  216.     NEARPLTe *p1,*p2;
  217.     for (p1=nplt->neartop,p2=NULL;  p1!=NULL;  p2=p1,p1=p1->next)
  218.     {
  219.         if (p1->plt == plt)
  220.         {
  221.             if (p2==NULL)
  222.                 nplt->neartop = p1->next;
  223.             else
  224.                 p2->next = p1->next;
  225.             p1->used = NO;
  226.         }
  227.     }
  228. }
  229.  
  230.  
  231. #endif /* if NO16==0 */
  232.  
  233.  
  234.  
  235. //     (global) grb_t カラー 000 に対する近似パレットリストのダンプ出力
  236. //                (デバッグ用関数)
  237. //-----------------------------------------------------------------------
  238.  
  239.  
  240. void __dumpNEARPLT0()
  241. {
  242. #if NO16==0
  243.     if (mode != MODE16)
  244.         return;
  245.     int tc = 0*256+0*16+0;
  246.     sprintf(debugmsg,"nearplt[%03x] dump:",tc);
  247.     DEBUG_MSG(debugmsg);
  248.     NEARPLTe *p;
  249.     p = (nearplt+tc)->neartop;
  250.     for ( ; p!=NULL; p=p->next)
  251.     {
  252.         sprintf(debugmsg, " %1x[%03x] d%4d", p->plt, plt16_get(p->plt), p->dist);
  253.         DEBUG_MSG(debugmsg);
  254.     }
  255. #endif
  256. }
  257.  
  258.  
  259. //     (global) 近似パレットリストおよびこのモジュールの初期化
  260. //-----------------------------------------------------------------------
  261.  
  262.  
  263. int plt16_init()
  264. {
  265. #if NO16==0
  266.     int i,j;
  267.     if (nearplt == NULL)
  268.     {
  269.         nearplt = calloc(sizeof(NEARPLT), 4096);
  270.         if (nearplt == NULL)
  271.         {
  272.             DEBUG_MSG("近似色リストバッファ 確保失敗");
  273.             return -1;
  274.         }
  275.         else
  276.             DEBUG_MSG("近似色リストバッファ 確保成功");
  277.     }
  278.     else
  279.         memset(nearplt, 0, sizeof(NEARPLT)*4096);
  280.     for (i=0; i<16; i++)
  281.         pltgrb[i] = _getplt(i);
  282.     for (i=0; i<4096; i++)
  283.         for (j=0; j<16; j++)
  284.             NEARPLT_ins(i,j);
  285.     __dumpNEARPLT0();
  286. #endif
  287.     return 0;
  288. }
  289.  
  290.  
  291. //     (global) 指定したパレット番号に対するパレットの設定
  292. //-----------------------------------------------------------------------
  293.  
  294.  
  295. void    plt16_set(int plt, grb_t grb)
  296. {
  297. #if NO16==0
  298.     int i;
  299.     for (i=0; i<4096; i++)
  300.         NEARPLT_del(i,plt);
  301.     _setplt(plt, grb);
  302.     pltgrb[plt] = grb;
  303.     for (i=0; i<4096; i++)
  304.         NEARPLT_ins(i,plt);
  305. #endif
  306. }
  307.  
  308.  
  309. //     (global) 指定したパレット番号に対するパレット内容を得る
  310. //-----------------------------------------------------------------------
  311.  
  312.  
  313. grb_t    plt16_get(int plt)
  314. {
  315. #if NO16==0
  316.     return pltgrb[plt];
  317. #else
  318.     return 0;
  319. #endif
  320. }
  321.  
  322.  
  323. //     (global) 指定した grb_t カラーの近似パレットを得る
  324. //-----------------------------------------------------------------------
  325.  
  326.  
  327. int        plt16_getnear(grb_t grb, int source_plt, int object_plt)
  328. // 指定されたRGBカラーに最も近いパレットを返す
  329. {
  330. #if NO16==0
  331.     NEARPLT *nplt;
  332.     nplt = nearplt + grb;
  333.     NEARPLTe *p;
  334.     p = nplt->neartop;
  335.     if (p->plt != source_plt)
  336.         return p->plt;
  337.     else    // 「一番近い色」がもとの色と同じ色の場合
  338.     {
  339.         int distmax = (nearplt+pltgrb[p->plt])->near[object_plt].dist;
  340.         // distmax = _min(distmax, _coldiff(pltgrb[source_plt], pltgrb[object_plt]));
  341.         for (p=p->next;  p!=NULL;  p=p->next)
  342.         {
  343.             if ((nearplt+pltgrb[p->plt])->near[object_plt].dist < distmax)
  344.                 return p->plt;
  345.         }
  346.         return object_plt;
  347.     }
  348. #else
  349.     return 0;
  350. #endif
  351. }
  352.  
  353.  
  354. //     (global) 指定した2つの grb_t カラーを混ぜ合わせる
  355. //-----------------------------------------------------------------------
  356.  
  357.  
  358. grb_t    plt16_gray(grb_t grb1, grb_t grb2, int gray)
  359. // gray : 0..256(grb2の「強さ」)
  360. {
  361. #if NO16==0
  362.     if (gray == 0)
  363.         return grb1;
  364.     else if (gray == 256)
  365.         return grb2;
  366.     else
  367.     {
  368.         gray = _min(256,_max(gray,0));
  369.         int gg,r1,r2,g1,g2,b1,b2,r,g,b;
  370.         gg = 256-gray;
  371.         g1 = (grb1>>8)&15;
  372.         r1 = (grb1>>4)&15;
  373.         b1 =  grb1 & 15;
  374.         g2 = (grb2>>8)&15;
  375.         r2 = (grb2>>4)&15;
  376.         b2 =  grb2 & 15;
  377.         g = (gg*g1 + gray*g2 + 128) / 256;
  378.         r = (gg*r1 + gray*r2 + 128) / 256;
  379.         b = (gg*b1 + gray*b2 + 128) / 256;
  380.         return (g<<8)|(r<<4)|b;
  381.     }
  382. #else
  383.     return 0;
  384. #endif
  385. }
  386.  
  387.  
  388. /* end of plt16.c */
  389.